﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Text;
using xKnight.Models;

namespace xKnight.Data
{
    public class DataLayer
    {
        public static void Save(Webpage page)
        {
            xKnightContext context = new xKnightContext();
            if (page.Id == 0)
            {
                context.Webpages.Add(page);
                context.SaveChanges();
            }
            else
            {
                context.Webpages.Attach(page);
                context.Entry(page).State = EntityState.Modified;
                context.SaveChanges();
            }
            context.Dispose();
        }

        public static void Save(Host host)
        {
            xKnightContext context = new xKnightContext();
            if (host.Id == 0)
            {
                context.Hosts.Add(host);
                context.SaveChanges();
            }
            else
            {
                context.Hosts.Attach(host);
                context.Entry(host).State = EntityState.Modified;

                context.SaveChanges();
            }

            context.Dispose();
        }

        public static void Save(WebCrawlingSetting crawlSetting)
        {
            xKnightContext context = new xKnightContext();
            if (crawlSetting.Id == 0)
            {
                context.WebCrawlingSettings.Add(crawlSetting);
                context.SaveChanges();
            }
            else
            {
                context.WebCrawlingSettings.Attach(crawlSetting);
                context.Entry(crawlSetting).State = EntityState.Modified;
                context.SaveChanges();
            }
            context.Dispose();
        }

        public static Host[] GetHosts(WebCrawlingSetting crawl)
        {
            xKnightContext context = new xKnightContext();
            Host[] results = null;

            if (crawl.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                results = context.Hosts.Where(h => h.CrawlId == crawl.Id).ToArray();
            }

            context.Dispose();
            return results;
        }

        public static void Save(XAttack xAttack)
        {
            xKnightContext context = new xKnightContext();
            if (xAttack.Id == 0)
            {
                context.XAttacks.Add(xAttack);
                for (int i = 0; i < xAttack.XAttackParams.Count; i++)
                {
                    context.XAttackParams.Add(xAttack.XAttackParams.ElementAt(i));    
                }
                context.SaveChanges();
            }
            else
            {
                context.XAttacks.Attach(xAttack);
                context.Entry(xAttack).State = EntityState.Modified;

                context.SaveChanges();
            }
            context.Dispose();
        }

        public static Form[] GetForms(Host[] hosts)
        {
            xKnightContext context = new xKnightContext();
            List<Form> results = new List<Form>();

            for (int i = 0; i < hosts.Length; i++)
            {
                if (hosts[i].Id <= 0)
                {
                    throw new InvalidOperationException("Nothing in database.");
                }
                else
                {
                    int id=hosts[i].Id;
                    Webpage[] webpages = context.Webpages.Where(wp=>wp.HostId==id).ToArray();
                    
                    for (int j = 0; j < webpages.Length; j++)
                    {
                        id=webpages[j].Id;
                        results.AddRange(context.Forms.Include("Webpage").Where(f => f.WebpageId ==id ).ToArray());    
                    }
                }
            }

            context.Dispose();

            return results.ToArray();
        }

        public static void Save(Attack attack)
        {
            xKnightContext context = new xKnightContext();
            if (attack.Id == 0)
            {
                context.Attacks.Add(attack);
                context.SaveChanges();
            }
            else
            {
                context.Attacks.Attach(attack);
                context.Entry(attack).State = EntityState.Modified;

                context.SaveChanges();
            }
            context.Dispose();
        }

        public static XAttackParam[] GetAttackParams(XAttack xAttack)
        {
            xKnightContext context = new xKnightContext();
            XAttackParam[] results = null;

            if (xAttack.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                results = context.XAttackParams.Where(ap=>ap.XAttackId==xAttack.Id && ap.FormElement.Type!="hidden").ToArray();
            }

            context.Dispose();
            return results;
        }

        public static XAttack[] GetXAttacks(Attack attack)
        {
            xKnightContext context = new xKnightContext();
            XAttack[] results = null;

            if (attack.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                results = context.XAttacks.Include("Form").Where(xa => xa.AttackId == attack.Id).ToArray();
            }

            context.Dispose();
            return results;
        }

        public static FormElement[] GetFormElements(Form form)
        {
            xKnightContext context = new xKnightContext();
            FormElement[] results = null;

            if (form.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                results = context.FormElements.Where(xa => xa.FormId == form.Id).ToArray();
            }

            context.Dispose();
            return results;
        }

        public static Attack GetAttack(int attackId)
        {
            xKnightContext context = new xKnightContext();

            Attack attack = context.Attacks.FirstOrDefault(a => a.Id == attackId);

            context.Dispose();
            return attack;
        }

        public static Webpage GetWebPage(int formId)
        {
            xKnightContext context = new xKnightContext();

            Form form = context.Forms.Include("Webpage").First(f => f.Id == formId);

            context.Dispose();
            return form.Webpage;
        }

        /*
        public static void CreateDb()
        {
            xKnightContext context = new xKnightContext();
            context.CreateDatabase();
        }

        public static bool IsDbExsit()
        {
            xKnightContext context = new xKnightContext();
            return context.DatabaseExists();
        }
         * 
         */

        public static void Save(Form form)
        {
            xKnightContext context = new xKnightContext();
            if (form.Id == 0)
            {
                context.Forms.Add(form);
                context.SaveChanges();
            }
            else
            {
                context.Forms.Attach(form);
                context.Entry(form).State = EntityState.Modified;

                context.SaveChanges();
            }
            context.Dispose();
        }

        public static void Save(CsrfAttack csrfAttack)
        {
            xKnightContext context = new xKnightContext();
            if (csrfAttack.Id == 0)
            {
                context.CsrfAttacks.Add(csrfAttack);
                context.SaveChanges();
            }
            else
            {
                context.CsrfAttacks.Attach(csrfAttack);
                context.Entry(csrfAttack).State = EntityState.Modified;

                context.SaveChanges();
            }
            context.Dispose();
        }

        public static void Save(CsrfAttackForm csrfAttackForm)
        {
            xKnightContext context = new xKnightContext();
            if (csrfAttackForm.Id == 0)
            {
                context.CsrfAttackForms.Add(csrfAttackForm);
                context.SaveChanges();
            }
            else
            {
                context.CsrfAttackForms.Attach(csrfAttackForm);
                context.Entry(csrfAttackForm).State = EntityState.Modified;

                context.SaveChanges();
            }

            context.Dispose();
        }

        public static CsrfAttack[] GetCsrfAttacks(Attack attack)
        {
            xKnightContext context = new xKnightContext();
            CsrfAttack[] results = null;

            if (attack.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                results = context.CsrfAttacks.Include(c=>c.CsrfAttackForms)
                    .Include(c=>c.Webpage)
                    .Include(c=>c.CsrfAttackForms.Select(af=>af.Form))
                    .Include(c=>c.CsrfAttackForms.Select(af=>af.Form).Select(f=>f.FormElements))
                    .Where(ca => ca.AttackId == attack.Id).ToArray();
            }

            context.Dispose();
            return results;
        }

        public static Form[] GetCsrfAttackOldForms(CsrfAttack attack)
        {
            xKnightContext context = new xKnightContext();
            List<Form> results = null;

            if (attack.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                results = context.Forms.Include("Webpage")
                    .Include("FormElements")
                    .Where(f => f.Webpage.Id == attack.WebpageId 
                    &&
                    context.CsrfAttackForms.All(cf=>cf.FormId!=f.Id))
                    .ToList();
            }

            context.Dispose();
            return results.ToArray();
        }

        public static CsrfAttackForm[] GetCsrfAttackForms(CsrfAttack attack)
        {
            xKnightContext context = new xKnightContext();
            CsrfAttackForm[] results = null;

            if (attack.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                results = context.CsrfAttackForms.Include("CsrfAttack")
                    .Include("Form")
                    .Where(f => f.CsrfAttackId == attack.Id).ToArray();
            }

            context.Dispose();
            return results;
        }

        public static void Save(CsrfToken csrfToken)
        {
            xKnightContext context = new xKnightContext();
            if (csrfToken.Id == 0)
            {
                context.CsrfTokens.Add(csrfToken);
                context.SaveChanges();
            }
            else
            {
                context.CsrfTokens.Attach(csrfToken);
                context.Entry(csrfToken).State = EntityState.Modified;
                
                context.SaveChanges();
            }

            context.Dispose();
        }

        public static void Save(Host host, System.Net.Cookie[] cookies)
        {
            xKnightContext context = new xKnightContext();

            for(int i=0;i<cookies.Length;i++)
            {
                RequestHostCookie requestHostCookie = new RequestHostCookie()
                    {
                        Comment = cookies[i].Comment,
                        CommentUri = cookies[i].CommentUri != null ? cookies[i].CommentUri.AbsolutePath : "",
                        Discard = cookies[i].Discard,
                        Domain = cookies[i].Domain,
                        Expired = cookies[i].Expired,
                        HostId = host.Id,
                        Name = cookies[i].Name,
                        Path = cookies[i].Path,
                        Port = cookies[i].Port,
                        Secure = cookies[i].Secure,
                        Value = cookies[i].Value,
                        Version = cookies[i].Version
                    };

                context.RequestHostCookies.Add(requestHostCookie);
            }

            context.SaveChanges();
        }

        public static System.Net.Cookie[] GetHostCookies(Form form)
        {
            xKnightContext context = new xKnightContext();
            List<Cookie> lstCookie = new List<Cookie>();

            if (form.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                var query = from webpage in context.Webpages
                            join host in context.Hosts on webpage.HostId equals host.Id
                            join cookie in context.RequestHostCookies on host.Id equals cookie.HostId
                            where webpage.Id==form.WebpageId
                            select cookie;

                foreach (var requestHostookie in query)
                {
                    Cookie cookie = new Cookie()
                    {
                        Comment = requestHostookie.Comment,
                        CommentUri = (requestHostookie.CommentUri!=null) ? new Uri(requestHostookie.CommentUri) : null,
                        Discard = requestHostookie.Discard,
                        Domain = requestHostookie.Domain,
                        Expired = requestHostookie.Expired,
                        Name = requestHostookie.Name,
                        Path = requestHostookie.Path,
                        Port = requestHostookie.Port,
                        Secure = requestHostookie.Secure,
                        Value = requestHostookie.Value,
                        Version = requestHostookie.Version.Value
                    };

                    lstCookie.Add(cookie);
                }

            }

            context.Dispose();
            return lstCookie.ToArray() ;
        }

        public static System.Net.Cookie[] GeHostCookies(Webpage webpage)
        {
            xKnightContext context = new xKnightContext();
            List<Cookie> lstCookie = new List<Cookie>();

            if (webpage.Id <= 0)
            {
                throw new InvalidOperationException("Nothing in database.");
            }
            else
            {
                var query = from host in context.Hosts 
                            join cookie in context.RequestHostCookies on host.Id equals cookie.HostId
                            where webpage.HostId==host.Id
                            select cookie;

                foreach (var requestHostookie in query)
                {
                    Cookie cookie = new Cookie()
                    {
                        Comment = requestHostookie.Comment,
                        CommentUri = (requestHostookie.CommentUri != "") ? new Uri(requestHostookie.CommentUri) : null,
                        Discard = requestHostookie.Discard,
                        Domain = requestHostookie.Domain,
                        Expired = requestHostookie.Expired,
                        Name = requestHostookie.Name,
                        Path = requestHostookie.Path,
                        Port = requestHostookie.Port,
                        Secure = requestHostookie.Secure,
                        Value = requestHostookie.Value,
                        Version = requestHostookie.Version.Value
                    };

                    lstCookie.Add(cookie);
                }

            }

            context.Dispose();
            return lstCookie.ToArray();
        }
    }
}
